/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package control;

import java.util.ArrayList;
import java.util.Collections;

/**
 * Clase que contiene la logica de las operaciones de Regresion/Interpolación y
 * Metodos estadisticos de Dispersión y de Tendencia
 *
 * @author Zergio
 */
public class ComponenteMatematico {

    //(8) Interpolacion Lagrange
    public boolean MetodoInterpolacion(ArrayList<Double> tiempos, ArrayList<Double> imagenes, int numeroPredicciones) {

        /**
         * Tiempos hace referencia a los momentos t medidos Imagenes hace
         * referencia a los valores de esas mediciones
         *
         * Se hace una interpolación de valores para minimo dos puntos de data y
         * maximo 4(las ultimas 4)
         *
         * retorna falso si ahi pocos datos (util para mostrar errores)
         */
        boolean flag = true;
        int n;
        double x, y;
        double matrizCalculo[][] = new double[4][2];

        System.out.println(imagenes.size() + "\n");

        if (tiempos.size() < 2) {
            flag = false;
        }
        if (tiempos.size() > 4) {
            do {
                System.out.println("1");
                tiempos.remove(1);
                imagenes.remove(1);
            } while (tiempos.size() > 4);

        }





        for (int j = 1; j <= tiempos.size(); j++) {

            matrizCalculo[j - 1][0] = tiempos.get(j - 1);

            matrizCalculo[j - 1][1] = imagenes.get(j - 1);
        }

        double valorTope = tiempos.get(tiempos.size() - 1);

        for (int i = 1; i <= numeroPredicciones; i++) {
            x = valorTope + i;

            switch (tiempos.size()) {
                case 2:
                    y = (((((x - matrizCalculo[1][0]) * matrizCalculo[0][1]) / (matrizCalculo[0][0] - matrizCalculo[1][0])) + (((x - matrizCalculo[0][0]) * matrizCalculo[1][1]) / (matrizCalculo[1][0] - matrizCalculo[0][0]))));
                    tiempos.add(x);
                    imagenes.add(y);


                    break;
                case 3:
                    y = ((x - matrizCalculo[1][0]) * (x - matrizCalculo[2][0]) * matrizCalculo[0][1]) / ((matrizCalculo[0][0] - matrizCalculo[1][0]) * (matrizCalculo[0][0] - matrizCalculo[2][0])) + ((x - matrizCalculo[0][0]) * (x - matrizCalculo[2][0]) * matrizCalculo[1][1]) / ((matrizCalculo[1][0] - matrizCalculo[0][0]) * (matrizCalculo[1][0] - matrizCalculo[2][0])) + ((x - matrizCalculo[1][0]) * ((x - matrizCalculo[0][0]) * matrizCalculo[2][1]) / ((matrizCalculo[2][0] - matrizCalculo[0][0]) * (matrizCalculo[2][0] - matrizCalculo[1][0])));
                    tiempos.add(x);
                    imagenes.add(y);
                    break;
                case 4:
                    y = ((x - matrizCalculo[1][0]) * (x - matrizCalculo[3][0]) * (x - matrizCalculo[2][0]) * matrizCalculo[0][1]) / ((matrizCalculo[0][0] - matrizCalculo[1][0]) * (matrizCalculo[0][0] - matrizCalculo[2][0]) * (matrizCalculo[0][0] - matrizCalculo[3][0])) + ((x - matrizCalculo[0][0]) * (x - matrizCalculo[2][0]) * (x - matrizCalculo[3][0]) * matrizCalculo[1][1]) / ((matrizCalculo[1][0] - matrizCalculo[0][0]) * (matrizCalculo[1][0] - matrizCalculo[2][0]) * (matrizCalculo[1][0] - matrizCalculo[3][0])) + ((x - matrizCalculo[0][0]) * (x - matrizCalculo[1][0]) * ((x - matrizCalculo[3][0]) * matrizCalculo[2][1]) / ((matrizCalculo[2][0] - matrizCalculo[0][0]) * (matrizCalculo[2][0] - matrizCalculo[1][0]) * (matrizCalculo[2][0] - matrizCalculo[3][0])) + ((x - matrizCalculo[0][0]) * (x - matrizCalculo[1][0]) * ((x - matrizCalculo[2][0]) * matrizCalculo[
3][1]) / ((matrizCalculo[3][0] - matrizCalculo[0][0]) * (matrizCalculo[3][0] - matrizCalculo[1][0]) * (matrizCalculo[3][0] - matrizCalculo[2][0]))));
                    tiempos.add(x);
                    imagenes.add(y);
                    break;
                default:
                    flag = false;
                    break;


            }
        }
        return flag;
    }

    public double Mediana(ArrayList<Double> datos) {

        Collections.sort(datos);



        if (datos.size() % 2 == 1) {
            return datos.get((datos.size() + 1) / 2 - 1);
        } else {
            double bajo = datos.get(datos.size() / 2 - 1);
            double alto = datos.get(datos.size() / 2);

            return (bajo + alto) / 2.0;
        }


    }

    public double Moda(ArrayList<Double> datos) {
        int cuentaMaxima = 0;
        double valorMaximo = 0;

        for (int i = 0; i < datos.size(); ++i) {
            int temp = 0;
            for (int j = 0; j < datos.size(); ++j) {
                if (datos.get(j) == datos.get(i)) {
                    ++temp;
                }
            }
            if (temp > cuentaMaxima) {
                cuentaMaxima = temp;
                valorMaximo = datos.get(i);
            }
        }

        return valorMaximo;
    }

    public double Media(ArrayList<Double> datos) {
        double sum = 0;
        for (int i = 0; i < datos.size(); i++) {
            sum += datos.get(i);
        }
        return sum / datos.size();
    }

    public double Desviacion(ArrayList<Double> datos) {
        return Math.sqrt(Varianza(datos));
    }

    public double RangoInterCuartilico(ArrayList<Double> datos) {
        ArrayList<Double> cuartiles = Cuartiles(datos);
        return cuartiles.get(2) - cuartiles.get(0);
    }

    public double Varianza(ArrayList<Double> datos) {
        double promedio = Media(datos);
        double sum = 0;
        for (int i = 1; i <= datos.size(); i++) {
            sum += Math.pow((datos.get(i) - promedio), 2);
        }
        return sum / (datos.size() - 1);
    }

    public ArrayList<Double> Cuartiles(ArrayList<Double> datos) {
        if (datos.size() < 3) {
            System.out.println("No se pueden tener menos de 3 elementos");
        }

        double mediana = Mediana(datos);

        ArrayList<Double> mitadInferior = SepararValoresMasPequenos(datos, mediana, true);
        ArrayList<Double> mitadSuperior = SepararValoresMasGrandes(datos, mediana, true);

        ArrayList<Double> resultado = new ArrayList<Double>();
        resultado.add(Mediana(mitadInferior));
        resultado.add(mediana);
        resultado.add(Mediana(mitadSuperior));

        return resultado;
    }

    public static ArrayList<Double> SepararValoresMasGrandes(ArrayList<Double> datos, double limite, boolean conIguales) {
        ArrayList<Double> nuevosDatos = new ArrayList<Double>();

        for (double valor : datos) {
            if (valor > limite || (valor == limite && conIguales)) {
                nuevosDatos.add(valor);
            }
        }

        return nuevosDatos;
    }

    public static ArrayList<Double> SepararValoresMasPequenos(ArrayList<Double> datos, double limite, boolean conIguales) {
        ArrayList<Double> nuevosDatos = new ArrayList<Double>();

        for (double valor : datos) {
            if (valor < limite || (valor == limite && conIguales)) {
                nuevosDatos.add(valor);
            }
        }

        return nuevosDatos;
    }
}
